/**
 * 
 */
package org.statewalker.parser.turtle;

import org.statewalker.dict.BaseDict;
import org.statewalker.validator.AbstractGrammar;
import org.statewalker.validator.ValidatorGrammarConfig;

/**
 * @see http://www.w3.org/TeamSubmission/turtle/#sec-grammar
 * <pre>
 * Turtle - Terse RDF Triple Language EBNF
 * [1]      turtleDoc   ::= statement*
 * [2]      statement   ::= directive '.' | triples '.' | ws+
 * [3]      directive   ::= prefixID | base
 * [4]      prefixID    ::= '@prefix' ws+ prefixName? ':' uriref
 * [5]      base    ::= '@base' ws+ uriref
 * [6]      triples ::= subject predicateObjectList
 * [7]      predicateObjectList ::= verb objectList ( ';' verb objectList )* ( ';')?
 * [8]      objectList  ::= object ( ',' object)*
 * [9]      verb    ::= predicate | 'a'
 * [10]     comment ::= '#' ( [^#xA#xD] )*
 * [11]     subject ::= resource | blank
 * [12]     predicate   ::= resource
 * [13]     object  ::= resource | blank | literal
 * [14]     literal ::= quotedString ( '@' language )? | datatypeString | integer | double | decimal | boolean
 * [15]     datatypeString  ::= quotedString '^^' resource
 * [16]     integer ::= ('-' | '+') ? [0-9]+
 * [17]     double  ::= ('-' | '+') ? ( [0-9]+ '.' [0-9]* exponent | '.' ([0-9])+ exponent | ([0-9])+ exponent )
 * [18]     decimal ::= ('-' | '+')? ( [0-9]+ '.' [0-9]* | '.' ([0-9])+ | ([0-9])+ )
 * [19]     exponent    ::= [eE] ('-' | '+')? [0-9]+
 * [20]     boolean ::= 'true' | 'false'
 * [21]     blank   ::= nodeID | '[]' | '[' predicateObjectList ']' | collection
 * [22]     itemList    ::= object+
 * [23]     collection  ::= '(' itemList? ')'
 * [24]     ws  ::= #x9 | #xA | #xD | #x20 | comment
 * [25]     resource    ::= uriref | qname
 * [26]     nodeID  ::= '_:' name
 * [27]     qname   ::= prefixName? ':' name?
 * [28]     uriref  ::= '<' relativeURI '>'
 * [29]     language    ::= [a-z]+ ('-' [a-z0-9]+ )*
 * [30]     nameStartChar   ::= [A-Z] | "_" | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
 * [31]     nameChar    ::= nameStartChar | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
 * [32]     name    ::= nameStartChar nameChar*
 * [33]     prefixName  ::= ( nameStartChar - '_' ) nameChar*
 * [34]     relativeURI ::= ucharacter*
 * [35]     quotedString    ::= string | longString
 * [36]     string  ::= #x22 scharacter* #x22
 * [37]     longString  ::= #x22 #x22 #x22 lcharacter* #x22 #x22 #x22
 * [38]     character   ::=  '\\u' hex hex hex hex | '\U' hex hex hex hex hex hex hex hex | '\\' | [#x20-#x5B] | [#x5D-#x10FFFF]
 * [39]     echaracter  ::= character | '\t' | '\n' | '\r'
 * [40]     hex ::= [#x30-#x39] | [#x41-#x46]
 * [41]     ucharacter  ::=  ( character - #x3E ) | '\>'
 * [42]     scharacter  ::=  ( echaracter - #x22 ) | '\"'
 * [43]     lcharacter  ::= echaracter | '\"' | #x9 | #xA | #xD
 * </pre>
 * @author kotelnikov
 *
 */
public class TurtleGrammar extends AbstractGrammar {

    public TurtleGrammar(ValidatorGrammarConfig config, String root) {
        super(config, root);
    }

    protected String getStyleContainer() {
        return getROOT();
    }

    @Override
    public void init() {
        initTURTLE_DOC();
        initSTATEMENT();
        initDIRECTIVE();
        initPREFIX_ID();
        initBASE();
        initTRIPLES();
    }

    /**
     * <pre>
     * [5]      base    ::= '@base' ws+ uriref
     * </pre>
     */
    private void initBASE() {
        init(TurtleDict1.BASE);
        defineParent(TurtleDict1.BASE, TurtleDict1.DIRECTIVE);
        defineTransition(
            TurtleDict1.DIRECTIVE,
            BaseDict.INITIAL,
            TurtleDict1._BASE,
            TurtleDict1._SPACES);
        defineTransition(
            TurtleDict1.DIRECTIVE,
            TurtleDict1._SPACES,
            TurtleDict1._URI_REF,
            TurtleDict1._URI_REF);
    }

    /**
     * <pre>
     *  [3]      directive   ::= prefixID | base
     * </pre>
     */
    private void initDIRECTIVE() {
        init(TurtleDict1.DIRECTIVE);
        defineParent(TurtleDict1.DIRECTIVE, TurtleDict1.STATEMENT);
        // directive ::= prefixId
        defineTransition(
            TurtleDict1.DIRECTIVE,
            BaseDict.INITIAL,
            TurtleDict1.PREFIX_ID,
            TurtleDict1.PREFIX_ID);
        // directive ::= base
        defineTransition(
            TurtleDict1.DIRECTIVE,
            BaseDict.INITIAL,
            TurtleDict1.BASE,
            TurtleDict1.BASE);
    }

    /**
     * <pre>
     * [4]      prefixID    ::= '@prefix' ws+ prefixName? ':' uriref
     * </pre>
     */
    private void initPREFIX_ID() {
        init(TurtleDict1.PREFIX_ID);
        defineParent(TurtleDict1.PREFIX_ID, TurtleDict1.DIRECTIVE);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            BaseDict.INITIAL,
            TurtleDict1._PREFIX,
            TurtleDict1._PREFIX);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            TurtleDict1._PREFIX,
            TurtleDict1._SPACES,
            TurtleDict1._SPACES);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            TurtleDict1._SPACES,
            TurtleDict1._PREFIX_NAME,
            TurtleDict1._PREFIX_NAME);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            TurtleDict1._PREFIX_NAME,
            TurtleDict1._TWO_POINTS,
            TurtleDict1._TWO_POINTS);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            TurtleDict1._SPACES,
            TurtleDict1._TWO_POINTS,
            TurtleDict1._TWO_POINTS);
        defineTransition(
            TurtleDict1.PREFIX_ID,
            TurtleDict1._TWO_POINTS,
            TurtleDict1._URI_REF,
            TurtleDict1._URI_REF);

    }

    /**
     * <pre>
     * [2]      statement   ::= directive '.' | triples '.' | ws+
     * </pre>
     */
    private void initSTATEMENT() {
        init(TurtleDict1.STATEMENT);
        defineParent(TurtleDict1.STATEMENT, TurtleDict1.TURTLE_DOC);
        // statement ::= directive '.'
        defineTransition(
            TurtleDict1.STATEMENT,
            BaseDict.INITIAL,
            TurtleDict1.DIRECTIVE,
            TurtleDict1.DIRECTIVE);
        defineTransition(
            TurtleDict1.STATEMENT,
            TurtleDict1.DIRECTIVE,
            TurtleDict1._POINT,
            TurtleDict1._POINT);
        // statement ::= triples '.'
        defineTransition(
            TurtleDict1.STATEMENT,
            BaseDict.INITIAL,
            TurtleDict1.TRIPLES,
            TurtleDict1.TRIPLES);
        defineTransition(
            TurtleDict1.STATEMENT,
            TurtleDict1.TRIPLES,
            TurtleDict1._POINT,
            TurtleDict1._POINT);
        // statement ::= ws+
        defineTransition(
            TurtleDict1.STATEMENT,
            BaseDict.INITIAL,
            TurtleDict1._SPACES,
            TurtleDict1._SPACES);
    }

    /**
     * <pre>
     * [6]      triples ::= subject predicateObjectList
     * </pre>
     */
    private void initTRIPLES() {
        init(TurtleDict1.TRIPLES);
        defineParent(TurtleDict1.TRIPLES, TurtleDict1.STATEMENT);
        defineTransition(
            TurtleDict1.TRIPLES,
            BaseDict.INITIAL,
            TurtleDict1.SUBJECT,
            TurtleDict1.SUBJECT);
        defineTransition(
            TurtleDict1.TRIPLES,
            TurtleDict1.SUBJECT,
            TurtleDict1.PREDICATE_OBJECT_LIST,
            TurtleDict1.PREDICATE_OBJECT_LIST);
    }

    /**
     * <pre>
     * [1]      turtleDoc   ::= statement*
     * </pre>
     */
    private void initTURTLE_DOC() {
        init(TurtleDict1.TURTLE_DOC);
        defineParent(TurtleDict1.TURTLE_DOC, getROOT());
        defineTransition(
            TurtleDict1.TURTLE_DOC,
            TurtleDict1.STATEMENT,
            TurtleDict1.STATEMENT);
    }

}